package bcontractor.propositional.factories;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.Assert.assertThat;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.junit.Before;
import org.junit.Test;

import bcontractor.api.SentenceSet;
import bcontractor.propositional.PropositionalSentence;

/**
 * Tests an PropositionalSentenceSetFactory
 * 
 * @author lundberg
 * 
 */
public class PropositionalSentenceSetFactoryShould {

	private static final int samples = 100;

	private static final int minSize = 5;

	private static final int maxSize = 8;

	private static final int nVariables = 10;

	private PropositionalSentenceSetFactory factory;

	@Before
	public void initialize() {
		Random random = new Random(31L);
		SentenceFactory<PropositionalSentence> clauseFactory = new ArbitraryClauseFactory(random, nVariables, minSize, maxSize);
		factory = new PropositionalSentenceSetFactory(clauseFactory, nVariables, 50);
	}

	@Test
	public void shouldGenerateCorrectSentenceSets() {
		for (int i = 0; i < samples; i++) {
			Set<Set<Integer>> clauses = new HashSet<Set<Integer>>();
			SentenceSet<PropositionalSentence> sentences = factory.create();
			for (PropositionalSentence sentence : sentences) {
				for (int[] clause : sentence.getClauses()) {
					Set<Integer> literalSet = new HashSet<Integer>();
					assertThat(clause.length, is(greaterThanOrEqualTo(minSize)));
					assertThat(clause.length, is(lessThanOrEqualTo(maxSize)));
					Set<Integer> atoms = new HashSet<Integer>();
					for (Integer literal : clause) {
						literalSet.add(literal);
						Integer atom = Math.abs(literal);
						assertThat(atoms, not(hasItem(atom)));
						assertThat(atom, is(greaterThan(0)));
						assertThat(atom, is(lessThanOrEqualTo(nVariables)));
						atoms.add(atom);
					}
					assertThat(clauses, not(hasItem(literalSet)));
					clauses.add(literalSet);
				}
			}
		}
	}
}
